﻿using System;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Powersource_UnitTests.TestBootstrappers;
using PowersourceUIToolkit;
using UCL.Powersource;
using UCL.Powersource.Mock;
using UCL.Powersource.TFS;
using UCL.Powersource.ViewModels;

namespace Powersource_UnitTests.ViewModels
{
    [TestClass]
    public class ViewModelTestWithAllMocks
    {
        bool WithPreview = true;
        Window wnd;
        DummyPowersourceBootStrapper bs;
        PowersourceMainViewModel MainVM;
        SettingsViewModel SettingsVM;
        ContentControlConductor CCConductor;
        IPowersourceExt IPowersourceExt;

        string newUri = "http://1.1.1.1:8080/tfs/TestProjectCollection2/";
        string newIldasmPath = "New path";
        string newFolder = "New Folder";
        string newDB = "New DB";
        //List<Assembly> Assemblies;

        [TestInitialize]
        public void StartUp()
        {

            bs = BootStrapperLoader.CreateDummyAll();
            wnd = null;
            if (WithPreview)
            {
                wnd = new Window();
                wnd.Width = 500;
                wnd.Height = 400;
                wnd.ShowInTaskbar = true;
                wnd.Show();
            }
            MainVM = ViewModelLocator.GetViewModel<PowersourceMainViewModel>();
            SettingsVM = ViewModelLocator.GetViewModel<SettingsViewModel>();
            CCConductor = new ContentControlConductor(wnd);
            CCConductor.Initialize();
            IPowersourceExt = PowersourceConnector.GetExtensibilityPoint();
            CCConductor.ActivateViewModel(MainVM);
            MainVM.Activate();
            MainVM.StartUpTFSConnect();
            //MainVM.ConnectToTFS(bs.IVsEnv.TeamFoundationServerExt.);
        }

        [TestCleanup]
        public void Clean()
        {
            wnd.Close();
            MainVM = null;
            SettingsVM = null; 
            bs.Dispose();
        }

        [TestMethod]
        public void MainVMTestConnectAndDisconnect()
        {
            Assert.IsTrue(MainVM.CurrentTfsTeamProjectCollection is DummyTfsTeamProjectCollection, "TfsTeamProjectCollection not correctly set after VS connection to TFS.");
            Assert.IsTrue(MainVM.PackageConfiguration is DummyPackageConfiguration, "PackageConfiguration not correctly set after VS connection to TFS.");
            Assert.IsTrue(MainVM.CurrentTfsTeamProjectCollectionConfiguration is DummyTeamProjectCollectionConfiguration, "TfsTeamProjectCollectionConfiguration not correctly set after VS connection to TFS.");
            Assert.AreEqual(5, MainVM.CurrentTfsTeamProjectConfigurations.Count, "TfsTeamProjectConfigurationCollection not correctly set after TFS connect.");
            MainVM.DisconnectFromTFS();
            Assert.IsNull(MainVM.CurrentTfsTeamProjectCollection, "TfsTeamProjectCollection not correctly set after VS disconnects from TFS.");
            Assert.IsNull(MainVM.CurrentTfsTeamProjectCollectionConfiguration, "TfsTeamProjectCollectionConfiguration not correctly set after VS disconnects from TFS.");
            Assert.IsNull(MainVM.CurrentTfsTeamProjectConfigurations, "TfsTeamProjectConfigurationCollection not correctly set after TFS disconnection.");

        }

        [TestMethod]
        public void MainVMTestVSChangeActiveContext()
        {
            var tpcc = MainVM.CurrentTfsTeamProjectCollection;
            ((DummyVSEnv)IoC.Get<IVSEnv>())._TeamFoundationServerExt.DummyProjectContext = new DummyProjectContextExt(newUri);
            Assert.AreNotEqual(tpcc, MainVM.CurrentTfsTeamProjectCollection, "TfsTeamProjectCollection not changed after change of VS TFS connection.");
            Assert.AreEqual(newUri, MainVM.CurrentTfsTeamProjectCollection.Uri.ToString(), "TfsTeamProjectCollection not correctly set after VS change of connection to TFS.");
            Assert.IsFalse(MainVM.CurrentTfsTeamProjectCollectionConfiguration.IsConnectedTo(tpcc), "TfsTeamProjectCollectionConfiguration not changed after change of VS TFS connection.");
            Assert.AreEqual(newUri, MainVM.CurrentTfsTeamProjectCollectionConfiguration.Uri, "TfsTeamProjectCollectionConfiguration not correctly set after VS change of connection to TFS.");
        }

        [TestMethod]
        public void SettingsVMTestSyncWithMainVM()
        {
            ChangeMainVMSettings();
            OpenSettings();
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.IldasmPath, SettingsVM.IldasmPath, "Dissasembler path not correctly synced on initialize");
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.LocalDropBasePath, SettingsVM.LocalDropBasePath, "Drop path not correctly synced on initialize");
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.CodeIndexDBServer, SettingsVM.CodeIndexDBServer, "DB Server not correctly synced on initialize");
            CloseSettings();
            ((DummyVSEnv)IoC.Get<IVSEnv>())._TeamFoundationServerExt.DummyProjectContext = new DummyProjectContextExt(newUri); 
            OpenSettings();
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.IldasmPath, SettingsVM.IldasmPath, "Dissasembler path not correctly synced on initialize");
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.LocalDropBasePath, SettingsVM.LocalDropBasePath, "Drop path not correctly synced on initialize");
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.CodeIndexDBServer, SettingsVM.CodeIndexDBServer, "DB Server not correctly synced on initialize");
        }

        [TestMethod]
        public void SettingsVMTestSave()
        {
            OpenSettings();
            SettingsVM.IldasmPath = newIldasmPath;
            SettingsVM.LocalDropBasePath = newFolder;
            SettingsVM.CodeIndexDBServer = newDB;
            SettingsVM.SaveChanges();
            DoEvents();
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.IldasmPath, newIldasmPath, "Dissasembler path not correctly synced on initialize");
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.LocalDropBasePath, newFolder, "Drop path not correctly synced on initialize");
            Assert.AreEqual(MainVM.CurrentTfsTeamProjectCollectionConfiguration.CodeIndexDBServer, newDB, "DB Server not correctly synced on initialize");
        }

        [TestMethod]
        public void SettingsVMTestDefaultsReset()
        {
            ChangeMainVMSettings();
            OpenSettings();
            SettingsVM.ResetToDefaults();
            Assert.AreEqual(MainVM.PackageConfiguration.DefaultIldasmPath, SettingsVM.IldasmPath, "Dissasembler path not correctly synced on initialize");
            Assert.AreEqual(MainVM.PackageConfiguration.DefaultLocalDropBasePath, SettingsVM.LocalDropBasePath, "Drop path not correctly synced on initialize");
            Assert.AreEqual(MainVM.PackageConfiguration.DefaultCodeIndexDBServer, SettingsVM.CodeIndexDBServer, "DB Server not correctly synced on initialize");
        }

        [TestMethod]
        public void SettingsVMTestDefaultRequestEvent()
        {
            OpenSettings();
            var defaultRequestRun = false;

            SettingsVM.FireDefaultDialog += (sender, e) => { defaultRequestRun = true; };
            SettingsVM.RequestResetToDefaults();
            Assert.IsFalse(defaultRequestRun, "Default event triggered with no changes.");

            SettingsVM.IldasmPath = newIldasmPath;
            SettingsVM.RequestResetToDefaults();
            Assert.IsTrue(defaultRequestRun, "Default event not triggered with changes.");
        }

        [TestMethod]
        public void SettingsVMTestSaveRequestEvent()
        {
            OpenSettings();
            var exitRequestRun = false;

            SettingsVM.FireSaveDialog += (sender, e) => { exitRequestRun = true; };
            CloseSettings();
            Assert.IsFalse(exitRequestRun, "Save event triggered with no changes.");
            Assert.IsFalse(SettingsVM.IsActivated, "Settings view does not properly close after save");

            OpenSettings();
            SettingsVM.IldasmPath = newIldasmPath;
            SettingsVM.RequestExit();
            Assert.IsTrue(exitRequestRun, "Save event not triggered with changes.");
        }

        private void CloseSettings()
        {
            SettingsVM.RequestExit();
            SettingsVM.Deactivate();
            MainVM.Activate();
            DoEvents();
        }

        private void OpenSettings()
        {
            MainVM.OpenSettings();
            MainVM.Deactivate();
            SettingsVM.Activate();
            DoEvents();
        }

        private void ChangeMainVMSettings()
        {

            MainVM.CurrentTfsTeamProjectCollectionConfiguration.IldasmPath = newIldasmPath;
            MainVM.CurrentTfsTeamProjectCollectionConfiguration.LocalDropBasePath = newFolder;
            MainVM.CurrentTfsTeamProjectCollectionConfiguration.CodeIndexDBServer = newDB;
        }

        void DoEvents()
        {
            DispatcherFrame f = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal,
            (SendOrPostCallback)delegate(object arg)
            {
                DispatcherFrame fr = arg as DispatcherFrame;
                fr.Continue = false;
            }, f);
            Dispatcher.PushFrame(f);
        }
    }
}
